package org.jeecg.common.util;

import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * RSA非对称加密算法工具类
 * @author muze
 */
public class RSAUtil {
    /**
     * RSA算法
     */
    private static final String RSA_ALGORITHM = "RSA";

    /**
     * 公私钥长度
     */
    private static final Integer KEY_LENGTH = 2048;

    /**
     * RSA算法公钥
     */
    private static final String RSA_PUBLIC_KEY = "tcjk@ldr!6688";

    /**
     * RSA算法私钥
     */
    private static final String RSA_PRIVATE_KEY = "ctt!tckj@1314";

    /**
     * 数据加密公钥
     */
    private static final String PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArBwEhnV0BWn/3QwQWrgDx5u7TrXyKAgR43INY/44E7f38cnhMPsgiX2HZp52S7EdZw7myIksh1pDmXvCD2/Lln4TfBPuHy3wqQZvnux6f5NpOcF+ZQJGStbQQq1gnSHQJSqYLjlwXk/KYqoIFX6FuvUIri0Xo4eIHoz+f0gZKJmGhDnK+7ZYxWeaqejxEiDYXjOSMCCZsM5isP2LHVyjPPhJbInzRVfMiB0PtwsLOakDl9pkcjSTr/atRi3d6Y8JFZ0INXF0HiN9+zdvmpamwPJ+hPv2sdcV8StGlGKI/F/wcXW2B7MleZnl68KC9G3TGEQ5x5Nx+tPyxdZxQFbLjwIDAQAB";

    /**
     * 数据解密公钥
     */
    private static final String PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsHASGdXQFaf/dDBBauAPHm7tOtfIoCBHjcg1j/jgTt/fxyeEw+yCJfYdmnnZLsR1nDubIiSyHWkOZe8IPb8uWfhN8E+4fLfCpBm+e7Hp/k2k5wX5lAkZK1tBCrWCdIdAlKpguOXBeT8piqggVfoW69QiuLRejh4gejP5/SBkomYaEOcr7tljFZ5qp6PESINheM5IwIJmwzmKw/YsdXKM8+ElsifNFV8yIHQ+3Cws5qQOX2mRyNJOv9q1GLd3pjwkVnQg1cXQeI337N2+alqbA8n6E+/ax1xXxK0aUYoj8X/BxdbYHsyV5meXrwoL0bdMYRDnHk3H60/LF1nFAVsuPAgMBAAECggEBAJFDLIaYB46yQqQ9FGidO4Nz64mpg3NKLF792lN1M7tg4MKQk6KVsoaZDnkMcee824YqS5siPBUZmEio7ce9oeWpD6T/5VEnoyHmLrvB+DpJHt0CdT2nx9BOsoQ0dYDqExXrd3o8PJ09VyIjRKNvoEuFmQf5QyRgtgCjHAItxh4+4erF6Tktiq++zvK8dzg0oEJyNzkGF+kjvXJBdioXt/bKU+rj4vdmPl7zWIemtYdhdki8OWo1tAozbBLAk31Na2Sl1ykaxvcvSIIznaSgEExpcSLvNaWt4DeRsMNwWNoVCmrJGutuJ/cF4hRsMtZnOxNjwOQrGDZIPXn+A388m8ECgYEA6CkPpbHmrfxXY8QZ5vac00L2xUXiANSiUp0C5+Duo9xM0Uhhvec3FwtWWpMK7o16nov5ppKF64TprQuKOVwY/hS/IKkRcdMHe1c/uQ/1/iGDW7A6h57MOsCiZhZCtUzzKNtkPG3NtMQj13gjVNqgEHTsiTepIy3JWEh3bolHRZECgYEAvchcgkfh4lEh6x5w8ND50nEm2vzvoLQhl14LF+KlBpOdZYMUra8FkhhiX02HCOtZu+f2GFxeM1FYq2BRgtBqpTPv4+gAvkwUhf+Ov3kBSiRfn+sSIIyuUm5d6GuIWzj0aLqflmd0OH19RW6tfAIBcLoGmCwdTtdCGuQsYZ0T7x8CgYAbituHXc6vL3Oyq04jX3iFe7lI+Bxy2scTI/t3RPEq0XTvkzW9UNPxUPACuNUgLfqxGowYneNzaIZMeEUCvxFb+1wdZNFj/pQxps0xiFo3twQdeY/IDSfPhJD/qX5qgeGLJFQE80XnPym9Y0xVwcYhja2OLeNMAB+V8KrymyiwcQKBgQCxe/HX/TWom8umwR9Kd4VLY3q9DhNkLVHE57RkMBe5YM+wIbhy/d2t1ZQaIL0KgF+5NaOXALswLwFHtJpGRneV7E6Ky2v2i9wdvPRY6Odl2UJ8ojCftDFK8eBs/jPVbBxW3UFmPXYZZnKDPpCMCqwiKjcElS0LkJBH6d//ohEEbQKBgGH6SxJ5dvQpLuF0kEg5LOnynjcYaEzhzto7ZB4vDbWCSF6JhaieWY1DuG0uS85MYE+ffaxgn447BjJujBhsveS7oyGcT+S/Jjh7HVKfquOGYUuoWqUDdIvq3Otysf55VB6QKVcYJ1gEOAqbDkrtmBpX5mzHcxyt0XUalfygLa81";

    /**
     * 生成数据加密公钥和数据解密私钥
     * @return 数据加密公钥和解密私钥键值对
     * @throws NoSuchAlgorithmException 不匹配算法异常
     */
    private static Map<String, Key> generatePublicAndPrivateKey() throws NoSuchAlgorithmException {
        // 创建KeyPairGenerator（Java加密架构(JCA)中的一个类）实例，用于生成公钥和私钥
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        // 初始化KeyPairGenerator实例，指定公钥和私钥长度，安全和性能综合考虑推荐2048
        keyPairGenerator.initialize(KEY_LENGTH);
        // 生成包含密钥对的实例
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 提取公钥
        Key publicKey = keyPair.getPublic();
        // 提取私钥
        Key privateKey = keyPair.getPrivate();
        // 创建一个初始容量位2的键值对，用于存储公私钥
        Map<String, Key> keyMap = new HashMap<>(2);
        // 将公钥放入键值对
        keyMap.put(RSA_PUBLIC_KEY, publicKey);
        // 将私钥放入键值对
        keyMap.put(RSA_PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 获取公钥
     * @param keyMap 公私钥键值对
     * @return 公钥字符串
     */
    private static String getPublicKey(Map<String, Key> keyMap) {
        // 从公私钥键值对中取出公钥
        Key publicKey = keyMap.get(RSA_PUBLIC_KEY);
        // 获取公钥字节数组
        byte[] publicKeyBytes = publicKey.getEncoded();
        // 使用Base64编码将公钥字节数组转换为字符串
        return Base64Utils.encodeToString(publicKeyBytes);
    }

    /**
     * 获取私钥
     * @param keyMap 公私钥键值对
     * @return 私钥字符串
     */
    private static String getPrivateKey(Map<String, Key> keyMap) {
        Key privateKey = keyMap.get(RSA_PRIVATE_KEY);
        byte[] privateKeyBytes = privateKey.getEncoded();
        return Base64Utils.encodeToString(privateKeyBytes);
    }

    /**
     * 公钥加密
     * @param needEncrypt 需要加密数据
     * @return 公钥加密后的字符串
     * @throws Exception 异常
     */
    public static String encryptByPublicKey(String needEncrypt) throws Exception {
        // 使用Base64编码将数据加密公钥转换为字节数组
        byte[] publicKeyBytes = Base64Utils.decodeFromString(PUBLIC_KEY);
        // 使用数据加密公钥字符数组创建一个X509EncodedKeySpec（密钥规范：公钥的ASN.1编码的一种表示形式）实例
        KeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        // 创建KeyFactory（JCE框架中的一个类）实例，用于转换公钥和私钥
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        // 从x509EncodedKeySpec（密钥规范：公钥的ASN.1编码的一种表示形式）中生成一个公钥
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        // 创建Cipher实例，用于加密解密
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        // 初始化Cipher实例，设置加密模式并指定要使用的公钥
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        // 加密为字节数组
        byte[] encryptBytes = cipher.doFinal(needEncrypt.getBytes());
        // 使用Base64编码将加密后的数组转换为字符串
        return Base64Utils.encodeToString(encryptBytes);
    }

    /**
     * 私钥解密
     * @param needDecrypt 需要解密数据
     * @return 私钥解密后的字符串
     * @throws Exception 异常
     */
    public static String decryptByPrivateKey(String needDecrypt) throws Exception {
        // 使用Base64编码将数据加密私钥转换为字节数组
        byte[] privateBytes = Base64Utils.decodeFromString(PRIVATE_KEY);
        // 使用数据解密私钥字符数组创建一个PKCS8EncodedKeySpec（密钥规范：私钥的ASN.1编码的一种表示形式）实例
        KeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateBytes);
        // 创建KeyFactory（JCE框架中的一个类）实例，用于转换公钥和私钥
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        // 从pkcs8EncodedKeySpec（密钥规范：私钥的ASN.1编码的一种表示形式）中生成一个私钥
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        // 创建Cipher实例，用于加密解密
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        // 初始化Cipher实例，设置解密模式并指定要使用的私钥
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // 使用Base64编码将需要解密数据转换为字节数组
        byte[] needDecryptBytes = Base64Utils.decodeFromString(needDecrypt);
        // 解密为字节数组
        byte[] decryptBytes = cipher.doFinal(needDecryptBytes);
        return new String(decryptBytes);
    }

    /**
     * 生成数据加密公钥和数据解密私钥后，将值替换到常量PUBLIC_KEY和PRIVATE_KEY
     * @param args 启动参数
     * @throws Exception 异常
     */
    public static void main(String[] args) throws Exception {
//        Map<String, Key> keyMap = generatePublicAndPrivateKey();
//        String publicKey = getPublicKey(keyMap);
//        String privateKey = getPrivateKey(keyMap);
//        System.out.println("数据加密公钥：" + publicKey);
//        System.out.println("数据解密私钥：" + privateKey);

        //替换公私钥后将上方代码注释，放开下面注释，测试加密解密功能
        String data = "Tckj@2024!";
        String encrypt = encryptByPublicKey(data);
        System.out.println("公钥加密后的数据：" + encrypt);
        String decrypt = decryptByPrivateKey(encrypt);
        System.out.println("私钥解密后的数据：" + decrypt);
    }
}
